﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace GeoParser
{
	/// <summary>
	/// An extension of a <see cref="GeoPoint"/> that also specifies a name and description.
	/// </summary>
	public class Waypoint : GeoPoint, IEquatable<Waypoint>
	{
		public string Name { get; private set; }
		public string Description { get; private set; }

		public Waypoint(double latitude, double longitude)
			: base(latitude, longitude)
		{
		}

		public Waypoint(string latitude, string longitude)
			: base(latitude, longitude)
		{
		}

		public Waypoint(double latitude, double longitude, string name, string description)
			: base(latitude, longitude)
		{
			Name = name;
			Description = description;
		}

		public Waypoint(string latitude, string longitude, string name, string description)
			: base(latitude, longitude)
		{
			Name = name;
			Description = description;
		}

		public Waypoint(XElement element)
		{
			if (element == null)
				throw new ArgumentNullException("element");

			Latitude = ParseDegrees(element.Attribute("lat").Value);
			Longitude = ParseDegrees(element.Attribute("lon").Value);
			Name = element.Element(element.Name.Namespace + "name").Value;
			Description = element.Element(element.Name.Namespace + "desc").Value;
		}

		public static Waypoint Clone(Waypoint orig)
		{
			if (orig == null)
				return null;
			return new Waypoint(orig.Latitude, orig.Longitude, orig.Name, orig.Description);
		}

		public override string ToString()
		{
			return string.Format("{0} ({1})", Name, Description);
		}

		public static IEnumerable<Waypoint> StartFrom(IEnumerable<Waypoint> unsorted, string name)
		{
			var sorted = new List<Waypoint>();

			var last = unsorted.Single(x => string.Equals(x.Name, name, StringComparison.CurrentCultureIgnoreCase));
			sorted.Add(last);

			while (unsorted.Any(x => !sorted.Contains(x)))
			{
				last = unsorted.Where(x => !sorted.Contains(x)).OrderBy(x => GeoPoint.DistanceBetween(x, last).Miles).First();
				sorted.Add(last);
			}

			return sorted;
		}

		#region IEquatable<Waypoint> Members

		public bool Equals(Waypoint other)
		{
			return other != null && base.Equals(other) && string.Equals(Name, other.Name) && string.Equals(Description, other.Description);
		}

		#endregion
	}
}